package net.zapasa.modelo.service;

import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;

import javax.annotation.Resource;

import net.zapasa.core.common.exception.BusinessException;
import net.zapasa.core.common.util.LogUtil;
import net.zapasa.core.common.util.StringUtil;
import net.zapasa.modelo.parser.impl.ParserGoogleShopping;
import net.zapasa.modelo.parser.interfaz.AbstractParserProducts;
import net.zapasa.modelo.parser.util.CustomHtmlMapper;

import org.apache.tika.metadata.Metadata;
import org.apache.tika.parser.ParseContext;
import org.apache.tika.parser.Parser;
import org.apache.tika.parser.html.HtmlMapper;
import org.apache.tika.parser.html.HtmlParser;
import org.broadleafcommerce.common.util.TransactionUtils;
import org.broadleafcommerce.core.catalog.dao.ProductCompetitiveDaoImpl;
import org.broadleafcommerce.core.catalog.dao.ProductDaoImpl;
import org.broadleafcommerce.core.catalog.domain.CompetitiveProduct;
import org.broadleafcommerce.core.catalog.domain.CompetitiveProductImpl;
import org.broadleafcommerce.core.catalog.domain.Product;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class ParserPriceCompetitiveService {
	
	private Parser parser;
	private ParseContext context;
	private Metadata metadata;

	@Resource(name="blProductDao")
	private ProductDaoImpl productDao;
	
	@Resource(name="zapProductCompetitiveDao")
	private ProductCompetitiveDaoImpl productCompetitiveDao;
	
	private final String url_google = "https://www.google.es/search?hl=es&output=search&tbm=shop&q=";
	
	
	public ParserPriceCompetitiveService() {
		super();
		// Inicializamos el parser
		parser = new HtmlParser();
		
		// Inicializamos el contexto..
		context = new ParseContext();
		context.set(Locale.class, new Locale("Es-es"));
		CustomHtmlMapper mapper = new CustomHtmlMapper();
		context.set(HtmlMapper.class, mapper);
		
		// Inicializamos los metadatos..
		metadata = new Metadata();
	}
	
	@Transactional(value = TransactionUtils.DEFAULT_TRANSACTION_MANAGER, rollbackFor=BusinessException.class)
	public void updateAll() throws BusinessException {
		
		List<CompetitiveProduct> productsCompetitive = null;
		List<CompetitiveProduct> newProductsCompetitive = null;
		
		// Obtengo todos los productos..
		List<Product> products = productDao.readAllActiveProducts();
		
		for(Product p : products){
			// Para cada producto que tenga query..
			if(!StringUtil.esNuloOVacio(p.getQuery())){

				// Obtengo los productos de la competencia..
				newProductsCompetitive = this.obtenerPreciosGoogleShopping(p.getQuery());
				
				// elimino los productos anteriores..
				productsCompetitive = productCompetitiveDao.readAllProductCompetitive(p.getId());
				for(CompetitiveProduct pe: productsCompetitive){
					productCompetitiveDao.delete(pe);
				}
				
				// Agrego los nuevos..
				for(CompetitiveProduct pe: newProductsCompetitive){
					pe.setProduct(p);
					productCompetitiveDao.createProductCompetitive(pe);
				}
				
				LogUtil.info(this.getClass(), "Se agregan {0} precios de la competencia para el producto {1} - {2}", newProductsCompetitive.size(), p.getId(), p.getName());
			}
		}

	}
	
	
	public List<CompetitiveProduct> obtenerPreciosGoogleShopping(String query) throws BusinessException{
		
		// TODO AZG pendiente pasar tambien el idioma de la busqueda..
		
		// Leemos una url			
		URLConnection connection;
		try {
			query = StringUtil.quitarAcentos(query);
			connection = new URL(url_google + query).openConnection();
		
			connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.11 (KHTML, like Gecko) Chrome/23.0.1271.95 Safari/537.11");
			connection.connect();

			InputStream stream = connection.getInputStream();
			List<CompetitiveProduct> products = this.obtenerPrecios(stream, new ParserGoogleShopping());
			return products;
			
		} catch (IOException e) {
			LogUtil.error(this.getClass(), e, "No se ha podido obtener los precios de la competencia con el parser google");
			throw new BusinessException("No se ha podido obtener los precios de la competencia con el parser google, detalles: " + e.getMessage(), e);
		}
	}
	
	public List<CompetitiveProduct> obtenerPrecios(InputStream fuente, AbstractParserProducts handler) throws BusinessException{
		try {
			// Realizamos el parseo..
			parser.parse(fuente, handler, metadata, context);
			List<CompetitiveProduct> products = handler.getProductos();
			
			// Elimino repetidos
			boolean existe;
			List<CompetitiveProduct> products_without_repeated = new ArrayList<CompetitiveProduct>();
			// Precio/Url
			Map<Double, String> price_products = new HashMap<Double, String>();
			for(CompetitiveProduct p : products){
				
				existe = false;
				// Si tienen el mismo precio y la url empieza igual, entonces ya existe..
				if(price_products.containsKey(p.getPrice())){
					if(price_products.get(p.getPrice()).startsWith(p.getUrl().substring(0, 50))){
						existe = true;
					}
				}
				
				// Si no existe, lo agrego..
				if(!existe){
					price_products.put(p.getPrice(), p.getUrl());
					products_without_repeated.add(p);	
				}
				
			}
			
			return products_without_repeated;
			
		} catch (Exception e) {
			LogUtil.error(this.getClass(), e, "No se ha podido obtener los precios de la competencia");
			throw new BusinessException("No se ha podido obtener los precios de la competencia, detalles: " + e.getMessage(), e);
		} 
	}
	

	public ParseContext getContext() {
		return context;
	}
	public void setContext(ParseContext context) {
		this.context = context;
	}
	
	
}
